/**
 * 
 */
package org.extdev.libraries.ltr;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.LinkedList;
import java.util.List;

import org.extdev.device.ltr.LTRCrate;
import org.extdev.device.ltr.LTRU1Crate;

import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;

/**
 * @author LAP
 *
 */
public class LTRAPILibraryFacade {
	
	private LTR.ByReference ltr;
	private LTRAPILibrary dllInstance = LTRAPILibrary.instance;
	
	public LTRAPILibraryFacade() throws LTRException {
		ltr = new LTR.ByReference();
		initilizeLTR();
	}
	
	public LTRAPILibraryFacade(Pointer pointer) {
		ltr = new LTR.ByReference(pointer);
	}
	
	public int getAddres() {
		return ltr.saddr;
	}
	
	public short getPort() {
		return ltr.sport;
	}
	
	public void setChannel(short value) {
		ltr.cc = value;
	}
	
	public short getChannel() {
		return ltr.cc;
	}
	
	public void setCrateSN(byte[] value) {
		for(int i = 0; i < value.length; i++) {
			ltr.csn[i] = value[i];
		}
	}
	
	public byte[] getCrateSN() {
		return ltr.csn;
	}
	
	public void initilizeLTR() throws LTRException {
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_Init(ltr));
	}
	
	public void openLTR() throws LTRException {
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_Open(ltr));
	}
	
	public void closeLTR() throws LTRException {
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_Close(ltr));
	}
	
	public boolean isOpened() {
		boolean flag = false;
		if (dllInstance.LTR_IsOpened(ltr) == 0) flag = true;;
		return flag;
	}
	
	public List<LTRCrate> getCrates() throws LTRException {
		LinkedList<String> cratesSerials = parseCratesArray();
		LinkedList<LTRCrate> list = new LinkedList<LTRCrate>();
		for(String s : cratesSerials) {
			if (!s.isEmpty()) {
				list.add(new LTRU1Crate(s));
			}
		}
		return list;
	}
	
	public LinkedList<Short> getModules() throws LTRException {
		short[] modulesArray = tryGetModulesArray();
		LinkedList<Short> modules = new LinkedList<Short>();
		for(short mid: modulesArray)
			if (mid != 0) modules.add(new Short(mid));
		return modules;
	}
	
	private short[] tryGetModulesArray() throws LTRException {
		ShortBuffer buf = ShortBuffer.allocate(LTRAPIConstants.MODULE_MAX);
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_GetCrateModules(ltr, buf));
		return buf.array();
	}
	
	private LinkedList<String> parseCratesArray() throws LTRException {
		ByteBuffer crates = getCratesArray();
		LinkedList<String> list = new LinkedList<String>();
		ByteBuffer parse = ByteBuffer.allocate(LTRAPIConstants.SERIAL_NUMBER_SIZE);
		int i = 0;
		for(byte switchByte : crates.array()){
				if(switchByte != 0) {
					parse.put(switchByte);
					i++;
				}
				else if(i != 0) {
					parse.flip();
					ByteBuffer ret = ByteBuffer.allocate(i);
					ret.put(parse);
					list.add(new String(ret.array()));
					i = 0;
				}
		}
		return list;
	}
	
	private ByteBuffer getCratesArray() throws LTRException {
		ByteBuffer crates = ByteBuffer.allocate(LTRAPIConstants.CRATE_MAX * LTRAPIConstants.SERIAL_NUMBER_SIZE);
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_GetCrates(ltr, crates));
		return crates;
	}
	
	public LTRData receive(int size, int timeout) throws LTRException {
		IntBuffer data = IntBuffer.allocate(size);
		IntBuffer tmark = IntBuffer.allocate(size);
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_Recv(ltr, data, tmark, size, timeout));
		return new LTRData(data, tmark);
	}
	
	public void serverRestart() throws LTRException {
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_ServerRestart(ltr));
	}
	
	public void serverShutdown() throws LTRException {
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_ServerShutdown(ltr));
	}
	
	public int getServerPriority() throws LTRException {
		IntByReference ret = new IntByReference();
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_GetServerProcessPriority(ltr, ret));
		return ret.getValue();
	}
	
	public void setServerPrioruty(int value) throws LTRException {
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_SetServerProcessPriority(ltr, value));
	}
	
	public int getLogLevel() throws LTRException {
		IntByReference ret = new IntByReference();
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_GetLogLevel(ltr, ret));
		return ret.getValue();
	}
	
	public void setLogLevel(int value, boolean permanent) throws LTRException {
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_SetLogLevel(ltr, value, permanent));
	}
	
	public int getServerVersion() throws LTRException {
		IntByReference ret = new IntByReference();
		LTRExceptionGenerator.throwLTRException(dllInstance.LTR_GetServerVersion(ltr, ret));
		return ret.getValue();
	}
}
